package cn.witsky.rtp2ws.client.ws;

import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.witsky.rtp2ws.Server;
import cn.witsky.rtp2ws.domain.Rtp;
import cn.witsky.rtp2ws.util.HttpUtil;
import cn.witsky.rtp2ws.util.LogUtil;
import cn.witsky.rtp2ws.util.MD5Util;
import cn.witsky.rtp2ws.util.SystemClock;
import io.netty.util.internal.StringUtil;

public class ClientUtil {
	private static Logger logger = LoggerFactory.getLogger(ClientUtil.class);
	private static String testUrl = "";
	public static BlockingQueue<Integer> proxyUrlQueue = null;
//	public static Set<String> proxyUrls = new HashSet<String>();
//	private static List<String> errorProxyList = new CopyOnWriteArrayList<String>();
	private static Map<String, Boolean> proxyStatusMap = new ConcurrentHashMap<String, Boolean>();
	private static Map<Integer, String> proxyUrlIndex = new HashMap<Integer, String>();

	private static Thread heartbeatThread = null;
	private static int heartbeatTime = 1;

	static void initProxyUrlQueue() {
		if(!proxyUrlIndex.isEmpty()) {
			int queueSize = proxyUrlIndex.size()*100;
			proxyUrlQueue = new ArrayBlockingQueue(queueSize);
			int i=1;
			while (i <= queueSize) {
				int j=i%proxyUrlIndex.size();
				if(j==0) {
					proxyUrlQueue.add(proxyUrlIndex.size());
				}else {
					proxyUrlQueue.add(j);
				}
				i++;
			}
		}

	}

	public static void setProxyUrl(String wsProxyUrl) {
		if (!StringUtil.isNullOrEmpty(wsProxyUrl)) {
			String[] urls = wsProxyUrl.split(",");
			int i = 1;
			for (String proxyUrl : urls) {
				if (!StringUtil.isNullOrEmpty(proxyUrl)) {
					proxyStatusMap.put(proxyUrl, false);
					proxyUrlIndex.put(i, proxyUrl);
					i++;
				}
			}
		}
		if(proxyStatusMap.isEmpty()) {
			return ;
		}
		initProxyUrlQueue();
		heartbeatThread = new Thread(new Runnable() {
			@Override
			public void run() {
				String heartbeatUrl = "";
				while (true) {
					try {
						for(int i=1;i<=proxyUrlIndex.size();i++) {
							String host = proxyUrlIndex.get(i);
							boolean status=proxyStatusMap.get(host);
							if(!status) {
								heartbeatUrl = "http://" + host + "/workingTest";
								net.sf.json.JSONObject result = HttpUtil.doGet(heartbeatUrl);
								if (result != null) {
									logger.info("websocket代理地址{}心跳检测成功", host);
									proxyStatusMap.put(host, true);
								} else {
									LogUtil.warn(null, "ClientUtil[setProxyUrl:89]", "websocket代理地址{}心跳检测失败", host);
								}
							}
						}
					} catch (Exception ex) {
						logger.error("执行心跳检测出现了异常:" + ex.getMessage());
					}
					LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(heartbeatTime));
				}
			}
		});
		heartbeatThread.setName("rtp2ws-wsProxyUrl-Heartbeat-Thread");
		heartbeatThread.start();

	}


	private static String getWsProxyUrl() {
		if (proxyUrlIndex.isEmpty()) {
			return "";
		} else {
			String proxyUrl = "";
			for (int i=1;i<=proxyUrlIndex.size();i++) {
				int index=-1;
				try {
					index=proxyUrlQueue.take();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if(index>-1) {
					String host=proxyUrlIndex.get(index);
					proxyUrlQueue.add(index);
					boolean status=proxyStatusMap.get(host);
					if(status) {
						proxyUrl=host;
						break;
					}
				}				
			}
			return proxyUrl;
		}
	}

	public static void setProxyStatus(String url) {
		if (url.indexOf("/wsProxy") > 0) {
			url = url.split("/wsProxy")[0];
			String host = url.replaceAll("ws://", "");
			proxyStatusMap.put(host, false);
		}
	}
	
	public static Client getClient(Rtp rtp, boolean retry) {
		return Client.getInstance(rtp, retry);
	}

	public static String formatUrl(Rtp rtp, boolean retry) {
		String wsProxyUrl = getWsProxyUrl();
		if (Server.useProxy) {
			if (wsProxyUrl.equals("")) {
				LogUtil.warn(null, "ClientUtil[setProxyUrl:89]", "代理地址都是不可用状态.....");
				return "";
			}
		}
		String wsUrl = getUrl(rtp, retry);
		if (Server.useProxy) {
			wsUrl = "ws://" + wsProxyUrl + "/wsProxy?wsUrl=" + URLEncoder.encode(wsUrl);
		}
		return wsUrl;
	}
	private static String getUserData(Rtp rtp) {
//		DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");     	
// 		//当前时间
// 		LocalDateTime now = LocalDateTime.now();
		com.alibaba.fastjson.JSONObject json=new com.alibaba.fastjson.JSONObject();
		json.put("callId", rtp.getCallId());
		json.put("ani", rtp.getCallInfo().getCaller());
		json.put("dnis", rtp.getCallInfo().getCalled());
		json.put("xNum", rtp.getCallInfo().getX());
		if(rtp.isCaller()) {
			json.put("asrType", 1);
		}else {
			json.put("asrType", 2);
		}
		json.put("callType", rtp.getCallInfo().getCallType());
		json.put("connectTm", rtp.getCallInfo().getConnectTm());
		json.put("offhkTm", rtp.getCallInfo().getOffhkTm());
//		json.put("asrTm",now.format(fmTime));
//		json.put("asrStaTm","");
//		json.put("asrCurTm","");
//		json.put("asrEndTm","");
		json.put("callStatus",1);
		json.put("agtId","");
//		json.put("asrText","");
//		json.put("asrTextId",0l);
		json.put("subId",0);
//		json.put("asrStatus",1);
		json.put("asrSendTm",SystemClock.now());
		json.put("callMode",rtp.getCallInfo().getCallMode());
		json.put("UserData",rtp.getCallInfo().getUser_data());
		json.put("user_data_key",rtp.getCallInfo().getUser_data_key());
		json.put("user_extdata_key",rtp.getCallInfo().getUser_extdata_key());
//		logger.info("rtp.getCallInfo().getUser_data():{}",json.get("UserData").getClass());
//		logger.info("json:{}",json.toString());
		return json.toString();
	}
	
	private static String getUrl(Rtp rtp, boolean retry) {
		String wsUrl = "";
		String appKey = Server.getAppKey();
		int  timestamp = (int) (SystemClock.now()/1000);
		StringBuilder inStr = new StringBuilder("");
		TreeMap<String, String> treeMap = new TreeMap<>();
		treeMap.put(UrlParam.APP_ID, Server.getAppId());
		treeMap.put(UrlParam.TIME_STAMP, timestamp+"");
		treeMap.put(UrlParam.APP_ID, Server.getAppId());
		if (!StringUtil.isNullOrEmpty(Server.getAddedInfo())) {
			treeMap.put(UrlParam.ADDED_INFO, Server.getAddedInfo());
		}
		String userData=getUserData(rtp);
		logger.debug("userData：{}",userData);
		treeMap.put(UrlParam.USER_DATA,userData );
		treeMap.put(UrlParam.USER_ID, rtp.getCallUser());
		if (retry) {
			treeMap.put(UrlParam.TYPE, "retransmission");
		}
		inStr.append(appKey);
		if (!StringUtil.isNullOrEmpty(testUrl)) {
			wsUrl = testUrl;
		} else {
			wsUrl = rtp.getWsUrl();
		}
		if (!wsUrl.endsWith("?")) {
			wsUrl = wsUrl + "?";
		}
		StringBuilder urlBuf = new StringBuilder(wsUrl);
		Iterator<Entry<String, String>> it = treeMap.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, String> next = it.next();
			String key = next.getKey();
			String value = next.getValue();
			if (key.equals(UrlParam.USER_DATA)) {
				logger.debug("task:{} user-data：{}",rtp.getRtpId(),value);
				value = URLEncoder.encode(value);
			}
			inStr.append(key).append(value);
			urlBuf.append(key).append("=").append(value).append("&");
		}
		inStr.append(appKey);
		String sign = "";
		try {
			sign = MD5Util.md5Encode(inStr.toString());
		} catch (Exception e) {
			logger.info("task:" + rtp.getRtpId() + "签名异常......", e);
		}
		urlBuf.append("_sign").append("=").append(sign);
		return urlBuf.toString();
	}

	public static void setHeartbeatTime(String heartbeatTimeStr) {
		if (!StringUtil.isNullOrEmpty(heartbeatTimeStr)) {
			ClientUtil.heartbeatTime = Integer.parseInt(heartbeatTimeStr);
		}

	}

	public static void setTestUrl(String testUrl) {
		ClientUtil.testUrl = testUrl;
	}

}
